package com.fr.spark;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 付荣
 * @version 创建时间：2019年6月21日 下午2:59:01 本质上就是动态规划！
 */
public class Viterbi {
    public static void main(String[] args) {
        // {健康，正常：0.5 ，冷 ：0.4 ，头晕： 0.1 ；发烧，正常：0.1 ，冷 ：0.3 ，头晕： 0.6 }
        float[][] matrix = new float[2][3];
        matrix[0][0] = 0.5f;
        matrix[0][1] = 0.4f;
        matrix[0][2] = 0.1f;
        matrix[1][0] = 0.1f;
        matrix[1][1] = 0.3f;
        matrix[1][2] = 0.6f;
        // transition_probability = {'健康': {'健康': 0.7, '发热': 0.3},'发热': {'健康': 0.4, '发热': 0.6}}
        float[][] transitionProbability = new float[2][2];
        transitionProbability[0][0] = 0.7f;
        transitionProbability[0][1] = 0.3f;
        transitionProbability[1][0] = 0.4f;
        transitionProbability[1][1] = 0.6f;
        List<FEEL> input = new ArrayList<>();
        input.add(FEEL.normal);
        input.add(FEEL.cool);
        input.add(FEEL.dizzy);
        int length = input.size();
        // 记录概率
        float rs[][] = new float[length][STATUS.values().length];
        // 记录转移状态
        STATUS rs1[][] = new STATUS[length][STATUS.values().length];
        // 初始化边界
        for (STATUS s : STATUS.values()) {
            rs[0][s.ordinal()] = s.startProbability * matrix[s.ordinal()][input.get(0).ordinal()];
            rs1[0][s.ordinal()] = null;
        }
        // 转移方程
        for (int i = 1; i < length; i++) {
            FEEL f = input.get(i);
            for (STATUS s : STATUS.values()) {
                float maxValue = 0f;
                STATUS status = null;
                for (STATUS ss : STATUS.values()) {
                    float tmp =
                        rs[i - 1][ss.ordinal()] * transitionProbability[ss.ordinal()][s.ordinal()]
                            * matrix[s.ordinal()][f.ordinal()];
                    if (tmp > maxValue) {
                        status = ss;
                        maxValue = tmp;
                    }
                }
                rs[i][s.ordinal()] = maxValue;
                rs1[i][s.ordinal()] = status;
            }
        }

        // 获取最佳数据展示
        STATUS status = null;
        float max = 0;
        for (STATUS s : STATUS.values()) {
            if (rs[length - 1][s.ordinal()] > max) {
                max = rs[length - 1][s.ordinal()];
                status = s;
            }
        }
        System.out.println("第" + length + "天:" + status.name + "\t" + max);
        for (int i = length - 1; i > 0; i--) {
            status = rs1[i][status.ordinal()];;
            System.out.println("第" + i + "天:" + status.name + "\t" + rs[i - 1][status.ordinal()]);

        }
    }
}

enum STATUS {
    healthy("健康", 0.6f), ill("发烧", 0.4f);

    String name;
    float startProbability;

    STATUS(String name, float startProbability) {
        this.name = name;
        this.startProbability = startProbability;
    }

}

enum FEEL {
    normal("正常"), cool("冷"), dizzy("头晕");
    String name;

    FEEL(String name) {
        this.name = name;
    }
}